package com.time.client.domain.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.time.admin.common.utils.CollectionUtils;
import com.time.client.common.enums.IsDeletedFlagEnum;
import com.time.client.domain.converter.CategoryBOConverter;
import com.time.client.domain.entity.CategoryBO;
import com.time.client.domain.redis.RedisUtil;
import com.time.client.domain.service.ClientCategoryDomainService;
import com.time.client.infra.basic.entity.Category;
import com.time.client.infra.basic.service.CategoryService;
import com.time.client.infra.basic.service.PostCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * 管理后台分类管理服务领域层实现类
 *
 * @author: HuangQi
 * @date: Created in 11:33 2025/10/9
 * @description: 管理后台分类管理服务领域层实现
 */
@Slf4j
@Service("clientCategoryService")
public class ClientCategoryDomainServiceImpl implements ClientCategoryDomainService {

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private PostCategoryService postCategoryService;

    @Autowired
    private RedisUtil redisUtil;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final long CATEGORY_CACHE_TIMEOUT_MINUTES = 15L;
    private static final long CATEGORY_CACHE_JITTER_MINUTES = 5L;
    private static final TimeUnit CATEGORY_CACHE_TIMEUNIT = TimeUnit.MINUTES;


    @Override
    public List<CategoryBO> queryPrimaryCategory() {
        if (log.isInfoEnabled()) {
            log.info("ClientCategoryDomainServiceImpl.queryPrimaryCategory");
        }

        String cacheKey = redisUtil.buildKey("client", "category", "primary");
        List<CategoryBO> cacheResult = getCache(cacheKey, new TypeReference<List<CategoryBO>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }

        // 调用service
        List<Category> categoryList = categoryService.queryPrimaryCategory();

        // 参数转换
        List<CategoryBO> categoryBOList = CategoryBOConverter.INSTANCE.convertEntityListToBO(categoryList);

        setCache(cacheKey, categoryBOList);
        // 返回结果
        return categoryBOList;
    }

    @Override
    public List<CategoryBO> queryCategoryByPrimary(CategoryBO categoryBO) {
        if (log.isInfoEnabled()) {
            log.info("ClientCategoryDomainServiceImpl.queryCategoryByPrimary.bo :{}", categoryBO);
        }

        String cacheKey = redisUtil.buildKey("client", "category", "children", serializeKey(categoryBO));
        List<CategoryBO> cacheResult = getCache(cacheKey, new TypeReference<List<CategoryBO>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }
        // 参数转换
        Category category = new Category();
        category.setParentId(categoryBO.getCategoryId());
        category.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        // 调用service
        List<Category> categoryList = categoryService.queryAllByCondition(category);

        // 参数转换
        List<CategoryBO> categoryBOList = CategoryBOConverter.INSTANCE.convertEntityListToBO(categoryList);

        setCache(cacheKey, categoryBOList);
        // 返回结果
        return categoryBOList;
    }

    @Override
    public List<CategoryBO> queryParentAndChildCategory() {
        if (log.isInfoEnabled()) {
            log.info("ClientCategoryDomainServiceImpl.queryParentAndChildCategory");
        }

        String cacheKey = redisUtil.buildKey("client", "category", "parent-child");
        List<CategoryBO> cacheResult = getCache(cacheKey, new TypeReference<List<CategoryBO>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }

        // 获取所有顶级分类
        List<Category> categoryList = categoryService.queryPrimaryCategory();
        List<CategoryBO> categoryBOList = CategoryBOConverter.INSTANCE.convertEntityListToBO(categoryList);

        // 获取所有顶级分类的子分类
        for (CategoryBO categoryBO : categoryBOList) {
            List<Category> childCategoryList = categoryService.queryByParentId(categoryBO.getCategoryId());
            if (CollectionUtils.isEmpty(childCategoryList)) {
                categoryBO.setChildCategoryList(List.of());
            } else {
                List<CategoryBO> childCategoryBOList = CategoryBOConverter.INSTANCE.convertEntityListToBO(childCategoryList);
                categoryBO.setChildCategoryList(childCategoryBOList);
            }
        }

        // 返回结果
        setCache(cacheKey, categoryBOList);
        return categoryBOList;
    }

    private <T> T getCache(String key, TypeReference<T> typeReference) {
        try {
            String cacheValue = redisUtil.get(key);
            if (cacheValue == null) {
                return null;
            }
            return OBJECT_MAPPER.readValue(cacheValue,
                    OBJECT_MAPPER.getTypeFactory().constructType(typeReference.getType()));
        } catch (Exception e) {
            log.warn("ClientCategoryDomainServiceImpl.getCache.error:key={}, msg={}", key, e.getMessage());
            return null;
        }
    }

    private void setCache(String key, Object value) {
        try {
            long ttl = CATEGORY_CACHE_TIMEOUT_MINUTES +
                    ThreadLocalRandom.current().nextLong(CATEGORY_CACHE_JITTER_MINUTES + 1);
            redisUtil.set(key, OBJECT_MAPPER.writeValueAsString(value), ttl, CATEGORY_CACHE_TIMEUNIT);
        } catch (Exception e) {
            log.warn("ClientCategoryDomainServiceImpl.setCache.error:key={}, msg={}", key, e.getMessage());
        }
    }

    private String serializeKey(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("ClientCategoryDomainServiceImpl.serializeKey.error:{}", e.getMessage());
            return String.valueOf(obj);
        }
    }
}
